package com.o2opuzi.lib.http;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;


/**
 * http 请求
 * @author yue han jiang
 * @date 2015年3月12日
 * @file_name HttpClient.java
 */
public class Http {
	
	
	private final String url;
	
	private HttpRequestBase requestBase;
	
	private RequestConfig config;

	private final Map<String, String> headers = new LinkedHashMap<String, String>();
	
	private final Map<String, Object> params = new LinkedHashMap<String, Object>();
	
	private CloseableHttpClient httpClient;

	public Map<String, Object>  getResultToMap(){ 
		return getResultToMap(null);
	}
	
	public Map<String, Object>  getResultToMap(String method){ 
		if(method != null){
			if(method.toUpperCase().equals("POST")){
				return doPost().toMap();
			}
		}
		return doGet().toMap();
	}
	
	
	
	public Http(String url){
		this(url,null);
	}
	
	public Http(String url,Map<String,Object> params) {
		if(url.startsWith("https")){
			SSLContext sslContext = null;
			try {
				sslContext = new SSLContextBuilder().loadTrustMaterial(null,new TrustStrategy() {
					@Override
					public boolean isTrusted(X509Certificate[] chain, String authType)
							throws CertificateException {
						return true;
					}
				}).build();
			} catch (KeyManagementException e) {
				throw new HttpException(e);
			} catch (NoSuchAlgorithmException e) {
				throw new HttpException(e);
			} catch (KeyStoreException e) {
				throw new HttpException(e);
			}
			this.httpClient = HttpClients.custom().setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext)).build();
		}else{
			this.httpClient = HttpClients.createDefault();
		}
		this.url = url;
		if(params != null){
			this.params.putAll(params);
		}
	}
	
	
	public Http addParam(String name,Object value){
		this.params.put(name, value);
		return this;
	}
	
	public Http addHeader(String name,String value){
		this.headers.put(name, value);
		return this;
	}

	public void setConfig(RequestConfig config) {
		this.config = config;
	}
	
	/**
	 * 执行
	 * @auther Y.hj
	 * @return
	 */
	private HttpResult doExecute(){
		try {
			setConfig().addHeader();
			HttpResponse resp = httpClient.execute(this.requestBase);
			return new HttpResult(resp.getStatusLine(),resp.getAllHeaders(),EntityUtils.toByteArray(resp.getEntity()));
		} catch (IOException e) {
			throw new HttpException(e);
		}finally{
			doClose();
		}
	}
	private Http setConfig() {
		if(config != null)
			requestBase.setConfig(config);
		return this;
	}
	
	public HttpResult doGet(){
		requestBase = new HttpGet(getParamsURI());
		return doExecute();
	}

	public HttpResult doPost(HttpEntity entity){
		requestBase = new HttpPost(url);
		HttpPost post = (HttpPost) this.requestBase;
		post.setEntity(entity);
		return doExecute();
	}
	
	public HttpResult doPost(){
		try {
			return doPost(new UrlEncodedFormEntity(addNameValuePairs(), "utf-8"));
		} catch (UnsupportedEncodingException e) {
			throw new HttpException(e);
		}
	}
	
	public HttpResult doPut(){
		try {
			return doPut(new UrlEncodedFormEntity(addNameValuePairs(),"utf-8"));
		} catch (UnsupportedEncodingException e) {
			throw new HttpException(e);
		}
	}
	
	private List<NameValuePair> addNameValuePairs(){
		List<NameValuePair> list = new ArrayList<NameValuePair>();
		for (Entry<String, Object> en : this.params.entrySet())
			list.add(new BasicNameValuePair(en.getKey(), en.getValue().toString()));
		return list;
	}
	
	public HttpResult doPut(HttpEntity entity){
		requestBase = new HttpPut(url);
		HttpPut httpPut = (HttpPut) this.requestBase;
		httpPut.setEntity(entity);
		return doExecute();
	}
	
	public HttpResult doDelete(){
		requestBase = new HttpDelete(getParamsURI());
		return doExecute();
	}
	
	private void addHeader(){
		for (Entry<String, String> header : headers.entrySet())
			requestBase.addHeader(header.getKey(), header.getValue());
	}
	
	private void doClose(){
		try {
			if(this.requestBase != null)
				this.requestBase.abort();
			if(this.httpClient != null)
				this.httpClient.close();
		} catch (IOException e) {
			throw new HttpException(e);
		}
	}
	
	private URI getParamsURI() {
		try {
			final StringBuilder urls = new StringBuilder(this.url);
			if(!this.params.isEmpty()){
				if(url.indexOf("?") == -1)
					urls.append("?");
				else
					urls.append("&");
				int size = 0;
				for (Entry<String, Object> en : this.params.entrySet()){
				    if(size == 0)
				    	urls.append(en.getKey()+"="+en.getValue());
				    else
				    	urls.append("&"+en.getKey()+"="+en.getValue());
				    size++;
				}
			}
			return new URI(urls.toString());
		} catch (Exception e) {
			throw new HttpException(e);
		}
	}
	
}
